home *** CD-ROM | disk | FTP | other *** search
- package IO::InnerFile;
-
- =head1 NAME
-
- IO::InnerFile - define a file inside another file
-
-
- =head1 SYNOPSIS
-
-
- ### Read a subset of a file:
- $inner = IO::InnerFile->new($fh, $start, $length);
- while (<$inner>) {
- ...
- }
-
-
- =head1 DESCRIPTION
-
- If you have a filehandle that can seek() and tell(), then you
- can open an IO::InnerFile on a range of the underlying file.
-
-
- =head1 PUBLIC INTERFACE
-
- =over
-
- =cut
-
- use Symbol;
-
- # The package version, both in 1.23 style *and* usable by MakeMaker:
- $VERSION = "2.110";
-
- #------------------------------
-
- =item new FILEHANDLE, [START, [LENGTH]]
-
- I<Class method, constructor.>
- Create a new inner-file opened on the given FILEHANDLE,
- from bytes START to START+LENGTH. Both START and LENGTH
- default to 0; negative values are silently coerced to zero.
-
- Note that FILEHANDLE must be able to seek() and tell(), in addition
- to whatever other methods you may desire for reading it.
-
- =cut
-
- sub new {
- my ($class, $fh, $start, $lg) = @_;
- $start = 0 if (!$start or ($start < 0));
- $lg = 0 if (!$lg or ($lg < 0));
-
- ### Create the underlying "object":
- my $a = {
- FH => $fh,
- CRPOS => 0,
- START => $start,
- LG => $lg,
- };
-
- ### Create a new filehandle tied to this object:
- $fh = gensym;
- tie(*$fh, $class, $a);
- return bless($fh, $class);
- }
-
- sub TIEHANDLE {
- my ($class, $data) = @_;
- return bless($data, $class);
- }
-
- sub DESTROY {
- my ($self) = @_;
- $self->close() if (ref($self) eq 'SCALAR');
- }
-
- #------------------------------
-
- =item set_length LENGTH
-
- =item get_length
-
- =item add_length NBYTES
-
- I<Instance methods.>
- Get/set the virtual length of the inner file.
-
- =cut
-
- sub set_length { tied(${$_[0]})->{LG} = $_[1]; }
- sub get_length { tied(${$_[0]})->{LG}; }
- sub add_length { tied(${$_[0]})->{LG} += $_[1]; }
-
- #------------------------------
-
- =item set_start START
-
- =item get_start
-
- =item add_start NBYTES
-
- I<Instance methods.>
- Get/set the virtual start position of the inner file.
-
- =cut
-
- sub set_start { tied(${$_[0]})->{START} = $_[1]; }
- sub get_start { tied(${$_[0]})->{START}; }
- sub set_end { tied(${$_[0]})->{LG} = $_[1] - tied(${$_[0]})->{START}; }
- sub get_end { tied(${$_[0]})->{LG} + tied(${$_[0]})->{START}; }
-
-
- #------------------------------
-
- =item binmode
-
- =item close
-
- =item flush
-
- =item getc
-
- =item getline
-
- =item print LIST
-
- =item printf LIST
-
- =item read BUF, NBYTES
-
- =item readline
-
- =item seek OFFFSET, WHENCE
-
- =item tell
-
- =item write ARGS...
-
- I<Instance methods.>
- Standard filehandle methods.
-
- =cut
-
- sub write { shift->WRITE(@_) }
- sub print { shift->PRINT(@_) }
- sub printf { shift->PRINTF(@_) }
- sub flush { "0 but true"; }
- sub binmode { 1; }
- sub getc { return GETC(tied(${$_[0]}) ); }
- sub read { return READ( tied(${$_[0]}), @_[1,2,3] ); }
- sub readline { return READLINE( tied(${$_[0]}) ); }
- sub getline { return READLINE( tied(${$_[0]}) ); }
- sub close { return CLOSE(tied(${$_[0]}) ); }
-
- sub seek {
- my ($self, $ofs, $whence) = @_;
- $self = tied( $$self );
-
- $self->{CRPOS} = $ofs if ($whence == 0);
- $self->{CRPOS}+= $ofs if ($whence == 1);
- $self->{CRPOS} = $self->{LG} + $ofs if ($whence == 2);
-
- $self->{CRPOS} = 0 if ($self->{CRPOS} < 0);
- $self->{CRPOS} = $self->{LG} if ($self->{CRPOS} > $self->{LG});
- return 1;
- }
-
- sub tell {
- return tied(${$_[0]})->{CRPOS};
- }
-
- sub WRITE {
- die "inner files can only open for reading\n";
- }
-
- sub PRINT {
- die "inner files can only open for reading\n";
- }
-
- sub PRINTF {
- die "inner files can only open for reading\n";
- }
-
- sub GETC {
- my ($self) = @_;
- return 0 if ($self->{CRPOS} >= $self->{LG});
-
- my $data;
-
- ### Save and seek...
- my $old_pos = $self->{FH}->tell;
- $self->{FH}->seek($self->{CRPOS}+$self->{START}, 0);
-
- ### ...read...
- my $lg = $self->{FH}->read($data, 1);
- $self->{CRPOS} += $lg;
-
- ### ...and restore:
- $self->{FH}->seek($old_pos, 0);
-
- $self->{LG} = $self->{CRPOS} unless ($lg);
- return ($lg ? $data : undef);
- }
-
- sub READ {
- my ($self, $undefined, $lg, $ofs) = @_;
- $undefined = undef;
-
- return 0 if ($self->{CRPOS} >= $self->{LG});
- $lg = $self->{LG} - $self->{CRPOS} if ($self->{CRPOS} + $lg > $self->{LG});
- return 0 unless ($lg);
-
- ### Save and seek...
- my $old_pos = $self->{FH}->tell;
- $self->{FH}->seek($self->{CRPOS}+$self->{START}, 0);
-
- ### ...read...
- $lg = $self->{FH}->read($_[1], $lg, $_[3] );
- $self->{CRPOS} += $lg;
-
- ### ...and restore:
- $self->{FH}->seek($old_pos, 0);
-
- $self->{LG} = $self->{CRPOS} unless ($lg);
- return $lg;
- }
-
- sub READLINE {
- my ($self) = @_;
- return undef if ($self->{CRPOS} >= $self->{LG});
-
- ### Save and seek...
- my $old_pos = $self->{FH}->tell;
- $self->{FH}->seek($self->{CRPOS}+$self->{START}, 0);
-
- ### ...read...
- my $text = $self->{FH}->getline;
-
- ### ...and restore:
- $self->{FH}->seek($old_pos, 0);
-
- #### If we detected a new EOF ...
- unless (defined $text) {
- $self->{LG} = $self->{CRPOS};
- return undef;
- }
-
- my $lg=length($text);
-
- $lg = $self->{LG} - $self->{CRPOS} if ($self->{CRPOS} + $lg > $self->{LG});
- $self->{CRPOS} += $lg;
-
- return substr($text, 0,$lg);
- }
-
- sub CLOSE { %{$_[0]}=(); }
-
-
-
- 1;
- __END__
-
- =back
-
-
- =head1 VERSION
-
- $Id: InnerFile.pm,v 1.4 2005/02/10 21:21:53 dfs Exp $
-
-
- =head1 AUTHOR
-
- Original version by Doru Petrescu (pdoru@kappa.ro).
-
- Documentation and by Eryq (eryq@zeegee.com).
-
- Currently maintained by David F. Skoll (dfs@roaringpenguin.com).
-
- =cut
-
-
-